iT邦幫忙

2024 iThome 鐵人賽

DAY 23
0
JavaScript

Javascript網頁程式管理系統系列 第 23

day 23 javascript結合line bot天氣管理規劃行程網頁程式管理系統

  • 分享至 

  • xImage
  •  

今天是第二十三我們可以寫一個javascript結合line bot天氣管理規劃行程網頁程式管理系統,以下是我的程式碼

  1. LINE Bot 基本設置
  2. 使用天氣 API 獲取天氣資訊
  3. 行程管理邏輯
  4. 網頁前端設計
  5. LINE Bot 回應設置

1. LINE Bot 基本設置

首先,創建一個 LINE Bot 並記下您的 Channel Access TokenChannel Secret

2. 天氣 API 設置

這裡使用 OpenWeatherMap API 來獲取天氣資訊。你需要去 OpenWeatherMap 註冊並獲得 API key。

# 安裝必要的 Node.js package
npm install @line/bot-sdk axios express

3. 設置 LINE Bot 和 Express 伺服器

const line = require('@line/bot-sdk');
const express = require('express');
const axios = require('axios');

const app = express();
const PORT = process.env.PORT || 3000;

const config = {
  channelAccessToken: 'YOUR_CHANNEL_ACCESS_TOKEN',
  channelSecret: 'YOUR_CHANNEL_SECRET',
};

// 初始化 LINE 客戶端
const client = new line.Client(config);

// OpenWeatherMap API 設置
const weatherAPIKey = 'YOUR_OPENWEATHERMAP_API_KEY';
const weatherAPIUrl = 'https://api.openweathermap.org/data/2.5/weather';

app.post('/webhook', line.middleware(config), (req, res) => {
  Promise
    .all(req.body.events.map(handleEvent))
    .then(result => res.json(result))
    .catch(err => console.log(err));
});

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  // 處理天氣查詢訊息
  if (event.message.text.includes('天氣')) {
    const city = event.message.text.replace('天氣', '').trim();
    return getWeather(city)
      .then(weatherMessage => {
        return client.replyMessage(event.replyToken, {
          type: 'text',
          text: weatherMessage
        });
      })
      .catch(err => {
        console.error(err);
        return client.replyMessage(event.replyToken, {
          type: 'text',
          text: '抱歉,我無法獲取天氣資訊。'
        });
      });
  }

  // 行程管理邏輯
  if (event.message.text.includes('行程')) {
    return manageSchedule(event.message.text)
      .then(scheduleMessage => {
        return client.replyMessage(event.replyToken, {
          type: 'text',
          text: scheduleMessage
        });
      });
  }

  return Promise.resolve(null);
}

async function getWeather(city) {
  try {
    const response = await axios.get(`${weatherAPIUrl}?q=${city}&appid=${weatherAPIKey}&units=metric&lang=zh_tw`);
    const data = response.data;
    const weather = data.weather[0].description;
    const temp = data.main.temp;
    return `目前${city}的天氣是${weather},氣溫約為 ${temp}°C。`;
  } catch (error) {
    return '無法獲取天氣資料,請檢查城市名稱是否正確。';
  }
}

function manageSchedule(text) {
  // 模擬行程管理邏輯,例如根據天氣自動調整
  let scheduleMessage = '行程規劃如下:\n';
  if (text.includes('戶外')) {
    scheduleMessage += '建議根據天氣選擇適合的戶外活動。\n';
  }
  if (text.includes('室內')) {
    scheduleMessage += '已為您安排適合的室內活動。\n';
  }
  return Promise.resolve(scheduleMessage);
}

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

4. 行程管理網頁前端

接著是網頁部分,提供一個簡單的介面讓用戶輸入地點來查詢天氣,並透過天氣來管理行程規劃:

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>天氣行程管理系統</title>
  <style>
    body { font-family: Arial, sans-serif; background-color: #f0f8ff; padding: 20px; }
    .container { max-width: 600px; margin: auto; text-align: center; }
    input, button { padding: 10px; margin: 5px; width: 80%; }
    #weather-result { margin-top: 20px; font-size: 1.2em; }
  </style>
</head>
<body>
  <div class="container">
    <h1>行程規劃天氣管理系統</h1>
    <p>請輸入城市來查詢天氣並安排行程:</p>
    <input type="text" id="city-input" placeholder="輸入城市名稱">
    <button onclick="getWeather()">查詢天氣</button>
    <div id="weather-result"></div>
  </div>

  <script>
    async function getWeather() {
      const city = document.getElementById('city-input').value;
      const apiKey = 'YOUR_OPENWEATHERMAP_API_KEY';
      const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric&lang=zh_tw`;

      try {
        const response = await fetch(apiUrl);
        const data = await response.json();

        if (data.cod === 200) {
          const weather = data.weather[0].description;
          const temp = data.main.temp;
          document.getElementById('weather-result').innerHTML = `
            ${city} 的天氣是 ${weather},氣溫 ${temp}°C。
          `;
        } else {
          document.getElementById('weather-result').innerText = '查無此城市,請確認輸入正確。';
        }
      } catch (error) {
        document.getElementById('weather-result').innerText = '無法獲取天氣資訊,請稍後再試。';
      }
    }
  </script>
</body>
</html>

5. LINE Bot 回應設置

確保將 Webhook URL 設置為伺服器的網址,並開啟 LINE Developer 中的 Webhook 功能,讓 Bot 可以接收到訊息。

1. 影片資料儲存陣列

let videos = [];

這是一個用來儲存所有影片資料的空陣列,每個影片物件包含 titlefile 屬性。在影片上傳時,我們會將影片的資訊加入這個陣列中,並在需要的時候更新或刪除。


2. 渲染影片列表 renderVideoList

function renderVideoList() {
    const videoList = document.getElementById('videoList');
    videoList.innerHTML = ''; // 清空列表,避免重複渲染

    if (videos.length === 0) {
        videoList.innerHTML = '<tr><td colspan="2">目前沒有影片。</td></tr>';
        return; // 如果沒有影片,顯示 "目前沒有影片"
    }

    videos.forEach((video, index) => {
        const row = document.createElement('tr'); // 創建一個表格行
        row.innerHTML = `
            <td>${video.title}</td> 
            <td>
                <button class="btn btn-warning btn-sm" onclick="editVideo(${index})">編輯</button>
                <button class="btn btn-danger btn-sm" onclick="deleteVideo(${index})">刪除</button>
            </td>
        `;
        videoList.appendChild(row); // 將每個影片資料添加到表格中
    });
}
  • videoList.innerHTML = '';:每次重新渲染影片列表前,先清空 videoList 內的內容,確保列表不會重複顯示。
  • 判斷影片數量:如果 videos 陣列為空,則顯示「目前沒有影片」的提示,並終止渲染流程。
  • forEach 遍歷:當有影片時,遍歷 videos 陣列,對每個影片創建一個 <tr>(表格列),並動態插入影片標題與操作按鈕(編輯與刪除)。

3. 影片上傳事件 uploadForm

document.getElementById('uploadForm').addEventListener('submit', function(event) {
    event.preventDefault(); // 阻止表單預設的提交行為(避免頁面重新載入)
    
    const title = document.getElementById('videoTitle').value; // 取得影片標題
    const file = document.getElementById('videoFile').files[0]; // 取得上傳的影片檔案

    if (!file) {
        alert('請選擇影片檔案。');
        return; // 如果沒有選擇檔案,提示並結束函數
    }

    const video = {
        title: title,
        file: file // 將影片標題和檔案保存為一個物件
    };

    videos.push(video); // 將新影片資料推入 videos 陣列中
    renderVideoList(); // 重新渲染影片列表
    this.reset(); // 重置表單內容
});
  • event.preventDefault():阻止表單提交的預設行為,這樣表單提交後不會刷新頁面。
  • 表單值提取
    • 透過 document.getElementById('videoTitle').value 取得影片標題。
    • 透過 document.getElementById('videoFile').files[0] 取得選擇的影片檔案。
  • 驗證檔案是否存在:如果使用者沒有選擇影片檔案,則顯示提示並結束函數。
  • 保存影片資料:將影片標題和檔案組合成一個物件,並加入 videos 陣列。
  • 重新渲染影片列表:影片資料更新後,呼叫 renderVideoList() 來更新 UI。
  • this.reset():重置表單,清空所有欄位。

4. 編輯影片 editVideo

function editVideo(index) {
    const newTitle = prompt('請輸入新的影片標題', videos[index].title); // 使用者輸入新標題
    if (newTitle !== null && newTitle.trim() !== '') { // 確保新標題有效
        videos[index].title = newTitle; // 更新影片標題
        renderVideoList(); // 重新渲染影片列表
    }
}
  • prompt():彈出一個對話框,讓使用者輸入新的影片標題。初始值為當前影片的標題。
  • 有效性檢查:如果使用者輸入了新標題,並且該標題不為空白或 null,則更新影片標題。
  • 更新並重新渲染:更新 videos 陣列中的標題後,重新渲染影片列表。

5. 刪除影片 deleteVideo

function deleteVideo(index) {
    if (confirm('確定要刪除此影片嗎?')) { // 彈出確認對話框
        videos.splice(index, 1); // 從陣列中刪除該影片
        renderVideoList(); // 重新渲染影片列表
    }
}
  • confirm():彈出確認對話框,詢問使用者是否確定刪除影片。如果使用者點擊「確認」,則繼續執行刪除操作。
  • videos.splice(index, 1):從 videos 陣列中移除指定索引的影片。splice() 是一個用來移除陣列中元素的方法,第一個參數是起始位置,第二個參數是刪除的數量(1 表示刪除一個元素)。
  • 重新渲染:刪除後,重新渲染影片列表。

6. 頁面初始化

renderVideoList();

這行程式在頁面載入時即被執行,確保影片列表一開始就正確顯示,即使當前 videos 陣列是空的也能顯示提示「目前沒有影片」。


總結:

  • videos 陣列 是這個系統的核心,負責儲存所有上傳的影片資料。
  • renderVideoList 函數會根據 videos 陣列中的內容動態生成影片列表,並在影片更新、刪除或修改後重新渲染頁面。
  • 使用者可以透過表單上傳影片、透過按鈕編輯或刪除影片,這些行為都會即時反映在頁面上。

上一篇
day 22 javascript線上影片教學平台網頁程式管理系統
下一篇
day 24 javascript自動整理筆記網頁程式管理系統
系列文
Javascript網頁程式管理系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言